<important>
<para>
Since these functions use GdkRGB for rendering, you must
- initialize GdkRGB before using any of them. You can do this by
- calling gdk_rgb_init() near the beginning of your program.
+ initialize GdkRGB before using any of them. If you are using
+ GNOME, gnome_init() will do this for you automatically.
+ Otherwise, you can do this by calling gdk_rgb_init() near the
+ beginning of your program.
+
</para>
</important>
2000-01-07 Jonathan Blandford <jrb@redhat.com>
+ * gdk-pixbuf/gdk-pixbuf-io.c: Added progressive animation loading.
+ * gdk-pixbuf/gdk-pixbuf-io.h: Added progressive animation loading.
+ * gdk-pixbuf/gdk-pixbuf-loader.c: Added progressive animation
+ loading.
+ * gdk-pixbuf/gdk-pixbuf-loader.h: Added progressive animation
+ loading.
+ * gdk-pixbuf/io-gif.c (image_load_increment): I think the
+ ref-counting mess is finally fixed. Added progressive animation
+ loading.
+
* doc/tmpl/gdk-pixbuf-loader.sgml: much longer long description
added.
frame->delay_time = -1;
frame->action = GDK_PIXBUF_FRAME_RETAIN;
- animation = g_new (GdkPixbufAnimation, 1);
+ animation = g_new0 (GdkPixbufAnimation, 1);
animation->ref_count = 1;
animation->n_frames = 1;
animation->frames = g_list_prepend (NULL, frame);
guint width, guint height,
gpointer user_data);
/* Needed only for animated images. */
-typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbuf *pixbuf,
- gint frame,
+typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
gpointer user_data);
typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
gpointer user_data);
enum {
AREA_UPDATED,
AREA_PREPARED,
+ FRAME_DONE,
+ ANIMATION_DONE,
CLOSED,
LAST_SIGNAL
};
/**
* gdk_pixbuf_loader_get_type:
- * @void:
- *
+ * @void:
+ *
* Registers the #GdkPixubfLoader class if necessary, and returns the type ID
* associated to it.
- *
+ *
* Return value: The type ID of the #GdkPixbufLoader class.
**/
GtkType
GTK_TYPE_INT,
GTK_TYPE_INT);
+ pixbuf_loader_signals[FRAME_DONE] =
+ gtk_signal_new ("frame_done",
+ GTK_RUN_LAST,
+ parent_class->type,
+ GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, frame_done),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ pixbuf_loader_signals[ANIMATION_DONE] =
+ gtk_signal_new ("animation_done",
+ GTK_RUN_LAST,
+ parent_class->type,
+ GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, animation_done),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
pixbuf_loader_signals[CLOSED] =
gtk_signal_new ("closed",
GTK_RUN_LAST,
if (!priv->closed)
gdk_pixbuf_loader_close (loader);
+ if (priv->animation)
+ gdk_pixbuf_animation_unref (priv->animation);
if (priv->pixbuf)
gdk_pixbuf_unref (priv->pixbuf);
MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
}
+static void
+gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame, gpointer loader)
+{
+ GdkPixbufLoaderPrivate *priv = NULL;
+
+ priv = GDK_PIXBUF_LOADER (loader)->private;
+
+ if (priv->animation == NULL) {
+ priv->animation = g_new0 (GdkPixbufAnimation, 1);
+ priv->animation->n_frames = 0;
+ priv->animation->ref_count = 1;
+ }
+
+ priv->animation->frames = g_list_append (priv->animation->frames, frame);
+ priv->animation->n_frames ++;
+ gtk_signal_emit (GTK_OBJECT (loader),
+ pixbuf_loader_signals[FRAME_DONE],
+ frame);
+}
+
+static void
+gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf, gpointer loader)
+{
+ gtk_signal_emit (GTK_OBJECT (loader),
+ pixbuf_loader_signals[ANIMATION_DONE]);
+}
+
\f
/**
* gdk_pixbuf_loader_new:
- * @void:
- *
+ *
* Creates a new pixbuf loader object.
- *
+ *
* Return value: A newly-created pixbuf loader.
**/
GdkPixbufLoader *
return 0;
}
- priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare, gdk_pixbuf_loader_update, NULL, NULL, loader);
+ priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare,
+ gdk_pixbuf_loader_update,
+ gdk_pixbuf_loader_frame_done,
+ gdk_pixbuf_loader_animation_done,
+ loader);
if (priv->context == NULL) {
g_warning("Failed to begin progressive load");
if( (* priv->image_module->load_increment) (priv->context, priv->header_buf, priv->header_buf_offset) )
return priv->header_buf_offset;
-
+
return 0;
}
nbytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
memcpy (priv->header_buf + priv->header_buf_offset, buf, nbytes);
-
+
priv->header_buf_offset += nbytes;
-
+
if(priv->header_buf_offset >= LOADER_HEADER_SIZE) {
if (gdk_pixbuf_loader_load_module(loader) == 0)
return 0;
/**
* gdk_pixbuf_loader_get_animation:
* @loader: A pixbuf loader
- *
+ *
* Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
* In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.
- *
+ * signal has been emitted by the loader. If the image is not an animation,
+ * then it will return NULL.
+ *
* Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
not enough data has been read to determine the information.
**/
gtk_signal_emit (GTK_OBJECT (loader),
pixbuf_loader_signals[CLOSED]);
}
+
void (* area_updated) (GdkPixbufLoader *loader,
guint x, guint y, guint width, guint height);
- void (* frame_done) (GdkPixbufLoader *loader, gint frame);
+ void (* frame_done) (GdkPixbufLoader *loader, GdkPixbufFrame *frame);
void (* animation_done) (GdkPixbufLoader *loader);
* -2 -> failure; abort the load
* -3 -> control needs to be passed back to the main loop
* \_ (most of the time returning 0 will get this, but not always)
+ *
* >1 -> for functions that get a guchar, the char will be returned.
*
* -jrb (11/03/1999)
/* progressive read, only. */
ModulePreparedNotifyFunc prepare_func;
ModuleUpdatedNotifyFunc update_func;
+ ModuleFrameDoneNotifyFunc frame_done_func;
+ ModuleAnimationDoneNotifyFunc anim_done_func;
gpointer user_data;
guchar *buf;
guint ptr;
if (context->prepare_func)
(* context->prepare_func) (context->pixbuf, context->user_data);
- if (context->animation) {
+ if (context->animation || context->frame_done_func) {
context->frame = g_new (GdkPixbufFrame, 1);
context->frame->x_offset = 0;
context->frame->y_offset = 0;
break;
}
context->frame->pixbuf = context->pixbuf;
- context->animation->n_frames ++;
- context->animation->frames = g_list_append (context->animation->frames, context->frame);
+ if (context->animation) {
+ context->animation->n_frames ++;
+ context->animation->frames = g_list_append (context->animation->frames, context->frame);
+ }
}
}
dest = gdk_pixbuf_get_pixels (context->pixbuf);
}
if (context->animation && context->state == GIF_GET_NEXT_STEP) {
+ (* context->frame_done_func) (context->frame,
+ context->user_data);
+
+ gdk_pixbuf_unref (context->pixbuf);
context->pixbuf = NULL;
context->frame = NULL;
}
context->state = GIF_START;
context->prepare_func = NULL;
context->update_func = NULL;
+ context->frame_done_func = NULL;
+ context->anim_done_func = NULL;
context->user_data = NULL;
context->buf = NULL;
context->amount_needed = 0;
context = new_context ();
context->prepare_func = prepare_func;
context->update_func = update_func;
+ context->frame_done_func = frame_done_func;
+ context->anim_done_func = anim_done_func;
context->user_data = user_data;
return (gpointer) context;
if (context->pixbuf)
gdk_pixbuf_unref (context->pixbuf);
-/* g_free (context->buf); */
+ if (context->animation)
+ gdk_pixbuf_animation_unref (context->animation);
+/* g_free (context->buf);*/
g_free (context);
}
*
* Authors: Mark Crichton <crichton@gimp.org>
* Federico Mena-Quintero <federico@gimp.org>
+ * Jonathan Blandford <jrb@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
TIFFClose (tiff);
if (context) {
- gdk_pixbuf_unref (pixbuf);
(* context->update_func) (pixbuf, 0, 0, w, h, context->user_data);
+ gdk_pixbuf_unref (pixbuf);
}
return pixbuf;
enum {
AREA_UPDATED,
AREA_PREPARED,
+ FRAME_DONE,
+ ANIMATION_DONE,
CLOSED,
LAST_SIGNAL
};
/**
* gdk_pixbuf_loader_get_type:
- * @void:
- *
+ * @void:
+ *
* Registers the #GdkPixubfLoader class if necessary, and returns the type ID
* associated to it.
- *
+ *
* Return value: The type ID of the #GdkPixbufLoader class.
**/
GtkType
GTK_TYPE_INT,
GTK_TYPE_INT);
+ pixbuf_loader_signals[FRAME_DONE] =
+ gtk_signal_new ("frame_done",
+ GTK_RUN_LAST,
+ parent_class->type,
+ GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, frame_done),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ pixbuf_loader_signals[ANIMATION_DONE] =
+ gtk_signal_new ("animation_done",
+ GTK_RUN_LAST,
+ parent_class->type,
+ GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, animation_done),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
pixbuf_loader_signals[CLOSED] =
gtk_signal_new ("closed",
GTK_RUN_LAST,
if (!priv->closed)
gdk_pixbuf_loader_close (loader);
+ if (priv->animation)
+ gdk_pixbuf_animation_unref (priv->animation);
if (priv->pixbuf)
gdk_pixbuf_unref (priv->pixbuf);
MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
}
+static void
+gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame, gpointer loader)
+{
+ GdkPixbufLoaderPrivate *priv = NULL;
+
+ priv = GDK_PIXBUF_LOADER (loader)->private;
+
+ if (priv->animation == NULL) {
+ priv->animation = g_new0 (GdkPixbufAnimation, 1);
+ priv->animation->n_frames = 0;
+ priv->animation->ref_count = 1;
+ }
+
+ priv->animation->frames = g_list_append (priv->animation->frames, frame);
+ priv->animation->n_frames ++;
+ gtk_signal_emit (GTK_OBJECT (loader),
+ pixbuf_loader_signals[FRAME_DONE],
+ frame);
+}
+
+static void
+gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf, gpointer loader)
+{
+ gtk_signal_emit (GTK_OBJECT (loader),
+ pixbuf_loader_signals[ANIMATION_DONE]);
+}
+
\f
/**
* gdk_pixbuf_loader_new:
- * @void:
- *
+ *
* Creates a new pixbuf loader object.
- *
+ *
* Return value: A newly-created pixbuf loader.
**/
GdkPixbufLoader *
return 0;
}
- priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare, gdk_pixbuf_loader_update, NULL, NULL, loader);
+ priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare,
+ gdk_pixbuf_loader_update,
+ gdk_pixbuf_loader_frame_done,
+ gdk_pixbuf_loader_animation_done,
+ loader);
if (priv->context == NULL) {
g_warning("Failed to begin progressive load");
if( (* priv->image_module->load_increment) (priv->context, priv->header_buf, priv->header_buf_offset) )
return priv->header_buf_offset;
-
+
return 0;
}
nbytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
memcpy (priv->header_buf + priv->header_buf_offset, buf, nbytes);
-
+
priv->header_buf_offset += nbytes;
-
+
if(priv->header_buf_offset >= LOADER_HEADER_SIZE) {
if (gdk_pixbuf_loader_load_module(loader) == 0)
return 0;
/**
* gdk_pixbuf_loader_get_animation:
* @loader: A pixbuf loader
- *
+ *
* Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
* In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.
- *
+ * signal has been emitted by the loader. If the image is not an animation,
+ * then it will return NULL.
+ *
* Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
not enough data has been read to determine the information.
**/
gtk_signal_emit (GTK_OBJECT (loader),
pixbuf_loader_signals[CLOSED]);
}
+
void (* area_updated) (GdkPixbufLoader *loader,
guint x, guint y, guint width, guint height);
- void (* frame_done) (GdkPixbufLoader *loader, gint frame);
+ void (* frame_done) (GdkPixbufLoader *loader, GdkPixbufFrame *frame);
void (* animation_done) (GdkPixbufLoader *loader);